package edu.pku.sei.autounit.reflect.java;

import java.lang.reflect.TypeVariable;

import edu.pku.sei.autounit.annotation.Context;
import edu.pku.sei.autounit.annotation.Filter;
import edu.pku.sei.autounit.annotation.AutoUnitMethod;
import edu.pku.sei.autounit.reflect.AbstractMethod;
import edu.pku.sei.autounit.reflect.Class;
import edu.pku.sei.autounit.reflect.Type;
import edu.pku.sei.autounit.reflect.TypeParameter;

public class JavaMethod extends AbstractMethod{
	
	private Type returnType;
	private Type [] parameters;
	private java.lang.reflect.Method javaMethod;
	private TypeFactory factory;
	
	protected JavaMethod(Class c,java.lang.reflect.Method javaMethod,TypeFactory factory) {

		super(javaMethod.getModifiers(),c,javaMethod.getName());
		this.javaMethod = javaMethod;
		this.factory = factory;
		
		Context context = javaMethod.getAnnotation(Context.class);
		Type [] contexts = null;
		if(context != null){
			java.lang.Class<?>[] cs= context.value();
			contexts = new Type[cs.length];
			for(int i=0;i<cs.length;i++)
				contexts[i] = factory.getType(cs[i], this);
		}
		else
			contexts = new Type[0];
		
		TypeVariable<?> [] tps = javaMethod.getTypeParameters();
		typeParameters = new TypeParameter[tps.length];
		for(int i =0 ;i<tps.length;i++){
			typeParameters[i] = new JavaTypeParameter(tps[i].getName());
			if(i<contexts.length)
				typeParameters[i].setContext(contexts[i]);
			
			java.lang.reflect.Type []tt = tps[i].getBounds();
			Type [] bs = new Type[tt.length];
			for(int j = 0; j<tt.length; j++)
				bs[j] = factory.getType(tt[j],this);
			typeParameters[i].setBounds(bs);
		}
	}

	
	public Type[] getParameters() {
		if(parameters == null){
			java.lang.reflect.Type []tt = javaMethod.getGenericParameterTypes();
			parameters = new Type[tt.length];
			for(int i=0;i<tt.length;i++){
				parameters[i] = factory.getType(tt[i],this);
			}
		}
		return parameters;
	}

	
	public Type getReturnType() {
		if(returnType == null){
			this.returnType = factory.getType(javaMethod.getGenericReturnType(),this);
		}
		return returnType;
	}

	
	public String getSource() {
		return null;
	}

	
	public java.lang.Class<?> getStrategy() {
		AutoUnitMethod t = javaMethod.getAnnotation(AutoUnitMethod.class);
		if(t== null)
			return null;
		else
			return t.value();
	}

	
	public boolean hasException() {
		return javaMethod.getExceptionTypes().length!=0;
	}

	
	public String[] getFilters() {
		Filter t = javaMethod.getAnnotation(Filter.class);
		if(t== null)
			return null;
		else
			return t.value();
	}
}
